# -*- coding: utf-8 -*-
# created on 2016/5/10
from sympy import ImageSet, Intersection, Complement, ConditionSet, solveset, Abs
from mathsolver.functions.sympy_utils import safe_degree, target_symbol
from mathsolver.functions.root.stepbystep import StepSolver
from mathsolver.functions.base import *
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSolve


class JieFangChen(BaseFunction):
    """
    JieFangChen().solver(BaseEq(['(-2)**a', '-8']))
    JieFangChen().solver(BaseEq(['sin(x)', '(1)/(2)']))
    JieFangChen().solver(BaseEq(['E**x', 't']))
    JieFangChen().solver(BaseEq(['sin(x)', '(1)/(2)']))
    JieFangChen().solver(BaseEq(['sqrt(x+6)', 'x']), BaseVariable("a"))
    JieFangChen().solver(BaseEq(['y', 'a*(x)**(2)-4*x-13*a']), BaseVariable("a"))
    JieFangChen().solver(BaseEq(['y', 'sqrt(x-1)+sqrt(1-x) + 1']))
    JieFangChen().solver(BaseEq(['(x)**(2)-3*x-10', '(x+a)*(x+b)']))
    JieFangChen().solver(BaseEq(['a+b', '0']))
    JieFangChen().solver(BaseEq(["y", "sqrt(1 - 2*x) + sqrt(2*x - 1) + sqrt((x-1)**2)"]))
    JieFangChen().solver(BaseEq(["Abs(a+2) + (b-1)**2 + Abs(c-1)", "0"]))
    JieFangChen().solver(BaseEq(["Abs(a+2) + (b-1)**2 + Abs(c-1)", "0"]))
    JieFangChen().solver(BaseEq(["x**2 + 2*x", "2"]))
    JieFangChen().solver(BaseEq(['y', 'sqrt(x-1)+sqrt(1-x) + 1']))
    JieFangChen().solver(BaseEq(['(x)**(2)-3*x-10', '(x+a)*(x+b)']))
    JieFangChen().solver(BaseEq(['a+b', '0']))
    JieFangChen().solver(BaseEq(["y", "sqrt(1 - 2*x) + sqrt(2*x - 1) + sqrt((x-1)**2)"]))
    JieFangChen().solver(BaseEq(["Abs(a+2) + (b-1)**2 + Abs(c-1)", "0"]))
    JieFangChen().solver(BaseEq(["Abs(a+2) + (b-1)**2 + Abs(c-1)", "0"]))
    JieFangChen().solver(BaseEq(["x**2 + 2*x", "2"]))
    """
    def type_1(self, f1):  # (a-2)^{a^{2}-4}=1
        ineqs = []
        if len(f1.args[0].free_symbols) > 0:
            ineqs.append((f1.args[0], "!=", S.Zero))

        if len(f1.args[1].free_symbols) > 0:
            ineqs.append((f1.args[1], S.Zero))

        self.output.append(base_gen(ineqs))
        return self

    def solver(self, *args):
        assert not isinstance(args[0], BaseGraph)
        _input = args
        f1, f2 = args[0].sympify()
        f1 = sympify(str(f1))
        f2 = sympify(str(f2))

        target = target_symbol(f1 - f2, args, self)
        symbol = default_symbol(f1 - f2, args, self)

        if f1.is_Symbol and f2.is_Number:
            pass  # simple
        else:
            self.label.add("解方程")
            self.steps.append(["", "解方程"])
            self.steps.append(["", "%s" % self.output_eq([f1, f2])])

        # (a-2)^{a^{2}-4}=1
        if f2 == 1 and f1.is_Pow and len(f1.args[0].free_symbols) > 0 and len(f1.args[1].free_symbols) > 0:
            return self.type_1(f1)

        # m^{6}•m^{2}=m^{a}
        # (x-4)^4 = ax^4 + bx^3 + cx^2

        ll = len((f1 - f2).free_symbols)
        if (isinstance(target, (tuple, list)) and (ll >= 3 and ll - len(target) == 1)) or len(
                f1.free_symbols) == 1 and len(f2.free_symbols) > 2:
            sym = (f1 - f2).free_symbols.difference(target).pop()
            f1 = f1.expand()
            f2 = f2.expand()
            if f1.is_Add and f2.is_Add:
                self.steps.append(["将方程展开为", self.output_eq([f1, f2])])
                eqs = []
                for i in range(8, 0, -1):
                    pow_token = Pow(sym, i)
                    a1, h1 = f1.as_independent(pow_token)
                    a2, h2 = f2.as_independent(pow_token)
                    c1 = h1.coeff(sym)
                    c2 = h2.coeff(sym)
                    if (c1 - c2).free_symbols:
                        eqs.append([c1, c2])

                    f1 = f1 - h1
                    f2 = f2 - h2

                if f2.free_symbols or f1.free_symbols:
                    eqs.append([f2, f1])

                assert len(eqs) > 0
                self.label.add("高次项展开")
                self.output.append(base_gen(eqs))
                return self

        # x^{2}+y^{2}+z^{2}-2x+4y-6z+14=0
        if f2.is_zero:
            eq = f1
        else:
            eq = f1 - f2

        parts = []
        for sym in eq.free_symbols:
            if eq.is_Add:
                aa, h = eq.as_independent(sym)
            else:
                aa, h = S.Zero, eq
            if isinstance(h, Abs) or h.is_Pow:
                parts.append(h)
                eq = aa
            elif safe_degree(h, sym) == 2 and h.is_Add:
                coeff_yici = 0
                coeff_erci = 0
                for arg in h.args:
                    if safe_degree(arg, sym) == 1:
                        coeff_yici = arg / sym
                    elif safe_degree(arg, sym) == 2:
                        coeff_erci = arg / (sym ** 2)

                v = coeff_yici / (2 * coeff_erci)
                parts.append(coeff_erci * (sym + coeff_yici / (2 * coeff_erci)) ** 2)
                eq = aa - coeff_erci * v ** 2

        if eq.is_zero and len(args) == 1:
            f = Add._from_args(parts)
            self.steps.append(["", "将方程变换为"])
            self.steps.append(["", "%s" % self.output_eq([f, S.Zero])])
        else:
            f = f1 - f2

        # |x - b | + sqrt(y + c) = 0
        if f.is_Add:
            args = f.args
            childrens = [get_all_child(arg, lambda tt: (tt.is_Pow and tt.free_symbols and (tt.args[1].is_even or (1 / tt.args[1]).is_even)) or isinstance(tt, Abs)) for arg in args]
            if all([len(child) > 0 for child in childrens]):
                eqs = []
                for child in childrens:
                    for arg in child:
                        eqs.append((arg.args[0], 0))

                self.steps.append(["", ",".join([new_latex(Eq(f1, f2)) for f1, f2 in eqs])])
                self.output.append(BaseEqs(eqs))
                self.label.add("0+0型问题")
                return self

        # sqrt(1-x) + sqrt(x - 1)
        parts = get_all_child((f1 - f2), lambda tt: tt.is_Pow and (1 / tt.args[1]).is_even and 1 / tt.args[1] > 0)
        args = set()
        sqrts = []
        for part in parts:
            for arg in args:
                if new_latex(part.args[0]) == new_latex(-arg.args[0]):
                    sqrts = [part, arg]
                    break
            if len(sqrts) == 0:
                args.add(part)

        eq = Eq(f1, f2)
        if len(sqrts) == 2:
            if (sqrts[0].args[0] + sqrts[1].args[0]).simplify().is_zero:
                assert len(sqrts[0].args[0].free_symbols) == 1
                sym = sqrts[0].args[0].free_symbols.pop()
                answer = list(solveset(sqrts[0].args[0], sym))
                self.steps.append(["由方程可得，", self.output_eqs([[tt.args[0], ">=", 0] for tt in sqrts])])
                self.steps.append(["", self.output_jie(answer, sym)])

                if len(eq.free_symbols) == 1:
                    self.output.append(BaseSymbolValue({sym: answer}))
                    self.label.add("由根式的定义解方程")
                    return self
                elif len(eq.free_symbols) == 2:
                    temp = eq.free_symbols
                    temp.remove(sym)
                    symbol2 = temp.pop()
                    output = {sym: answer, symbol2: []}
                    for ans in answer:
                        rest = (f1 - f2).subs({sym: ans})
                        answer = list(solveset(rest, symbol2))
                        assert len(answer) <= 1
                        output[symbol2].extend(answer)
                    self.steps.append(["带入原方程得，", self.output_jies(output)])
                    self.output.append(BaseSymbolValue(output))
                    self.label.add("由根式的定义解方程")
                    return self
                else:
                    raise ValueError

        # assert len(symbols) <= 1, symbols

        if "I" in str(f1 - f2):
            answer = solveset(eq, symbol)
        elif get_all_child(f1, lambda xx: isinstance(xx, Abs) and xx.args[0].has(symbol)):
            answer = solveset(eq, symbol, S.Reals)
        else:
            try:
                answer = solveset(eq, symbol, S.Reals)
                assert not isinstance(answer, (ConditionSet, EmptySet))
            except Exception:
                answer = solveset(eq, symbol)

        if "ConditionSet" in str(answer) or "ImageSet" in str(answer):
            answer = MathematicaSolve().solver(_input[0], BaseVariable(symbol)).output[0]
            self.steps.append(["", answer.printing()])
            self.output.append(answer)
            return self

        answer = self.extract_answer(answer)

        if not self.verbose:
            if f1.is_Symbol and not f2.has(symbol):
                self.label.clear()
            else:
                self.steps.append(["", self.output_jie(answer, symbol)])
        else:
            try:
                sl = StepSolver(f1, f2).solve()
                assert len(sl.answers) != 0
                self.steps += sl.printing()
            except Exception:
                self.steps.append(["", self.output_jie(answer, symbol)])

        self.output.append(BaseSymbolValue({symbol: answer}))
        return self

    def extract_answer(self, answer):

        if isinstance(answer, Interval):
            # self.steps.append(["", self.output_interval(symbol, answer)])
            # self.output.append(BaseSymbolValue({symbol:answer}))
            answer = answer
        elif isinstance(answer, Intersection):
            finite = [arg for arg in answer.args if isinstance(arg, FiniteSet)]
            assert len(finite) == 1, "more than one intersection"
            answer = finite[0]
        elif isinstance(answer, Complement):
            intersection = [arg for arg in answer.args if isinstance(arg, Intersection)][0]
            finite = [arg for arg in intersection.args if isinstance(arg, FiniteSet)]
            assert len(finite) == 1, "more than one intersection"
            answer = finite[0]
        elif isinstance(answer, Union):
            answers = []
            for arg in answer.args:
                sub_answer = self.extract_answer(arg)
                if isinstance(sub_answer, list):
                    answers.append(FiniteSet(*sub_answer))
                else:
                    answers.append(sub_answer)

            answer = Union(answers)

        if "ImageSet" in str(answer):
            if isinstance(answer, ImageSet):
                answer = [answer.lamda(0)]
            elif isinstance(answer, Union) and isinstance(answer.args[0], ImageSet):
                answer = [answer.args[0].lamda(0)]
        elif not isinstance(answer, Interval):
            answer = [ans.cancel() for ans in answer]

        return answer


if __name__ == '__main__':
    pass
